// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: daniel

#pragma once

#include <memory>
#include <string>
#include <vector>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/bitmex/api_util/auth_key.h"
#include "coin2/exchange/order/prex.pb.h"
#include "coin2/exchange/prex/symbology/product.h"

class PrexNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::PrexRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using ActionType = coin2::exchange::base::order::NativePrivateClient::ActionType;
  using PrexProduct = coin2::exchange::prex::symbology::PrexProduct;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order) {
    switch (order.type()) {
      case OrderExecutionProto::SUBMIT_ORDER: {
        auto order_spec = OrderSpec::FromProto(order.order_spec());
        auto params =
            GetRestOrderParams(*order_spec, order.proc_order_id(), order.orig_proc_order_id());
        return PlaceOrder(params);
      }
      case OrderExecutionProto::CANCEL_ORDER: {
        auto order_spec = OrderSpec::FromProto(order.order_spec());
        auto params =
            GetRestOrderParams(*order_spec, order.proc_order_id(), order.orig_proc_order_id());
        return CancelSingleOrder(params);
        return nullptr;
      }
      default: {
        return nullptr;
      }
    }
  }

  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query) override {
    RestParams params;
    switch (query.type()) {
      case RestQueryProto::QUERY_ACCOUNT_BALANCE: {
        return QueryWallet();
      }
      case RestQueryProto::QUERY_OPEN_ORDERS: {
        return QueryOpenOrders();
      }
      case RestQueryProto::QUERY_SINGLE_ORDER: {
        params.set_order_id(query.exchange_order_id());
        return QueryOrdersByIds(params);
      }
      default: {
        return nullptr;
      }
    }
  }

 public:
  explicit PrexNativePrivateClient(const MarketExchangeApi& mea, const NativeClientConfig& config);
  std::shared_ptr<AsioHttpContext> QueryAuth();
  std::shared_ptr<AsioHttpContext> QueryWallet();
  std::shared_ptr<AsioHttpContext> QueryOpenOrders();
  std::shared_ptr<AsioHttpContext> QueryOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOrdersByIds(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryExecution(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryHistConversions(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> AmendOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelSingleOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelOrders(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> AmendOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> SubmitConversion(const ConversionSpec&) override;

  RestParams GetRestOrderParams(
      const OrderSpec& order_spec,
      int64_t proc_order_id,
      int64_t orig_proc_order_id);

  RestParams GetRestCancelParams(const IOrderContext& order_context);

  RestParams GetRestAmendParams(
      const OrderSpec& order_spec,
      const std::string& exchange_order_id,
      int64_t proc_order_id,
      int64_t orig_proc_order_id);

 protected:
  std::string auth_token_;
};
